import axios, {
    AxiosError,
    AxiosHeaderValue,
    AxiosRequestConfig,
    AxiosResponseHeaders,
    InternalAxiosRequestConfig,
} from 'axios';
import { action, makeObservable } from 'mobx';
import RootStore from 'store/RootStore';

const api = axios.create({
    baseURL: 'https://api.github.com/',
    headers: {
        Accept: 'application/vnd.github+json',
        'X-GitHub-Api-Version': '2022-11-28',
    },
});

api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    const access_token = localStorage.getItem('access_token');
    if (access_token) {
        config.headers.Authorization = `Bearer ${access_token}`;
    }

    return config;
});

api.interceptors.response.use(
    (response) => response,
    (error: AxiosError<never>) => {
        if (error.response?.status === 401) {
            localStorage.removeItem('access_token');
            RootStore.githubOAuth.setAccessToken(null);
        }
        return Promise.reject(error).catch((error: AxiosError) => {
            throw error;
        });
    },
);

export enum FetchMeta {
    FETCHING = 'FETCHING',
    FETCHED = 'FETCHED',
    ERROR = 'ERROR',
    INITIAL = 'INITIAL',
}

export default class ApiStore {
    readonly getApiRequest = <ResponseType>(
        link: string,
        config?: AxiosRequestConfig,
    ): Promise<{
        data: ResponseType;
        headers: AxiosResponseHeaders | Partial<Record<string, AxiosHeaderValue>>;
    }> => api.get<ResponseType>(link, config).then((res) => ({ data: res.data, headers: res.headers }));

    readonly postApiRequest = <ResponseType, BodyType>(
        link: string,
        body?: BodyType,
        config?: AxiosRequestConfig,
    ): Promise<{
        data: ResponseType;
        headers: AxiosResponseHeaders | Partial<Record<string, AxiosHeaderValue>>;
    }> => api.post<ResponseType>(link, body, config).then((res) => ({ data: res.data, headers: res.headers }));

    constructor() {
        makeObservable<ApiStore>(this, {
            getApiRequest: action,
            postApiRequest: action,
        });
    }
}
